package com.lmxdawn.api.dnf.service.impl;

import cn.hutool.core.date.SystemClock;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.lmxdawn.api.admin.util.CacheUtils;
import com.lmxdawn.api.common.api.ApiAssert;
import com.lmxdawn.api.common.api.RedisKeyEnum;
import com.lmxdawn.api.dnf.dto.SysSmsCodeDto;
import com.lmxdawn.api.dnf.dto.WxpayConfig;
import com.lmxdawn.api.dnf.service.ISmsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.lmxdawn.api.common.api.UserErrorCode.*;

/**
 * 短信服务实现类
 */
@Slf4j
@Service
public class SmsServiceImpl implements ISmsService {

    private static final int SMS_LIMIT_REDIS_TIMEOUT = 24 * 60 * 60;

    @Resource
    RestTemplate restTemplate;
    @Resource
    WxpayConfig wxpayConfig;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public void sendLoginVerifyCode(String phone) {
        this.checkSendLimit(phone);
        String code = RandomUtil.randomNumbers(6);
        Map<String, String> params = new HashMap<>();
        params.put("code", code);
        //修改短信模板id
        SendSmsResponse sendSmsResponse = sendSms(phone, "诸城天思网络科技", "SMS_472475506", params);
        if (Objects.isNull(sendSmsResponse)) {
            ApiAssert.fail(SEND_SMS_ERROR);
        }
        String sendCode = sendSmsResponse.getCode();
        String message = sendSmsResponse.getMessage();
        log.info("--->sendSms, sendCode: {}, message: {}", sendCode, message);


        SysSmsCodeDto smsCodeDto = new SysSmsCodeDto();
        smsCodeDto.setCode(code);
        // 获取当前时间戳（单位为毫秒）
        smsCodeDto.setTimestamp(SystemClock.now());
        smsCodeDto.setStatus(0);
        // 存入redis缓存，过期时间5分钟
        String redisKey = String.format(RedisKeyEnum.LOGIN_SMS_CODE.getKey(), phone);
        CacheUtils.set(redisKey, JSON.toJSONString(smsCodeDto), 300L);
        this.setSendLimit(phone);
    }

    @Override
    public void sendSaleNotify(String orderId, String phone) {
        Map<String, String> params = new HashMap<>();
        params.put("code", orderId.substring(orderId.length() - 4));
        SendSmsResponse sendSmsResponse =
                sendSms(phone, "诸城天思网络科技", "SMS_478385446", params);
        log.info("--->sendSms, orderId: {}, phone: {}, resp: {}", orderId, phone, sendSmsResponse);
    }
    @Override
    public void sendBuyerNotify(String orderId, String phone) {
        Map<String, String> params = new HashMap<>();
        params.put("code", orderId.substring(orderId.length() - 4));
        SendSmsResponse sendSmsResponse =
                sendSms(phone, "诸城天思网络科技", "SMS_478630441", params);
        log.info("--->sendSms, orderId: {}, phone: {}, resp: {}", orderId, phone, sendSmsResponse);
    }

    public String getAccessToken() {
        String apiUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" +
                wxpayConfig.getAppID() + "&secret=" + wxpayConfig.getAppSecret();
        Map<String, String> response =
                restTemplate.getForObject(apiUrl, Map.class);
        System.out.println(JSON.toJSONString(response));
        return response != null ? response.get("access_token") : null;
    }

    @Override
    public void sendTemplateMessageNotify(String openId) {
        String accessToken = this.getAccessToken();
        String apiUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken;
        Map<String, Object> message = new HashMap<>();
        message.put("touser", openId);
        message.put("template_id", "okeneU3_eQVTI9rwyPNq3F9Ypx4XGywJ7XsEN8LK7hI");
        HashMap<String, Object> data = new HashMap<>();
        HashMap<String, Object> thing19 = new HashMap<>();
        HashMap<String, Object> character_string8 = new HashMap<>();
        data.put("thing19", thing19);
        data.put("character_string8", character_string8);
        thing19.put("value", "AA");
        character_string8.put("value", "BB");
        message.put("data", data);
        message.put("url", "http://www.5808d.com/");
        String s = JSONUtil.toJsonStr(message);
        String response = HttpUtil.createPost(apiUrl).body(s)
                .header("Content-type", "application/json")
                .execute()
                .charset("UTF-8")
                .body();
//        String response = restTemplate.postForObject(apiUrl, message, String.class);
        System.out.println(response);
    }

    /**
     * @return : com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse
     * @Description : 调用阿里云sendSmsAPI短信服务
     * @Author : chenkunming
     * @Date : 2024/9/05
     * @params : [smsBean]
     */
    public static SendSmsResponse sendSms(String receivers, String signName, String templateId, Map<String, String> templateParams) {
        IAcsClient acsClient = getiAcsClient();
        if (null == acsClient) {
            return null;
        }
        SendSmsRequest request = new SendSmsRequest();
        //必填:待发送手机号
        request.setPhoneNumbers(receivers);
        //必填:短信签名
        request.setSignName(signName);
        if (StringUtils.isBlank(templateId)) {
            log.warn("templateId is blank, please check the code");
            return null;
        }
        //必填:短信模板
        request.setTemplateCode(templateId);
        //可选:模板中的变量替换JSON串
        if (null != templateParams && !templateParams.isEmpty()) {
            request.setTemplateParam(JSON.toJSONString(templateParams));
        }
        // TODO 选填-上行短信扩展码(无特殊需求用户请忽略此字段)
        //request.setSmsUpExtendCode("90997");
        // TODO 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
//        request.setOutId("yourOutId");
        log.info("---->sendSms receiver: {},templateParams:{}", request.getPhoneNumbers(), templateParams);
        SendSmsResponse sendSmsResponse = null;
        try {
            sendSmsResponse = acsClient.getAcsResponse(request);
        } catch (ClientException e) {
            log.error(e.getMessage());
        }
        return sendSmsResponse;
    }

    /**
     * @return : com.aliyuncs.IAcsClient
     * @Description : 获取阿里云发送短信配置类
     * @Author : chenkunming
     * @Date : 2024/9/05
     * @params : []
     */
    private static IAcsClient getiAcsClient() {
        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");
        //初始化acsClient,暂不支持region化
        try {
            //阿里云accessKeyId和accessKeySecret
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI5tHofweeeQE34PoVMhA1", "uT8lirwrOVp6sbVUo3SkFCfCFW37kw");
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", "Dysmsapi", "dysmsapi.aliyuncs.com");
            return new DefaultAcsClient(profile);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
    }


    /**
     * 短信发送次数限制
     *
     * @param phone 手机号
     */
    private void checkSendLimit(String phone) {
        Assert.hasLength(phone, "手机号不允许为空");
        String smsLimitKey = RedisKeyEnum.SMS_LIMIT.getKey() + phone;
        long currentTime = System.currentTimeMillis() / 1000;

        long twentyFourHoursAgo = currentTime - 24 * 60 * 60;
        long oneHoursAgo = currentTime - 60 * 60;
        long oneMinuteAgo = currentTime - 60;

        // 设置BoundZSetOperations以便进行有序集合的操作
        BoundZSetOperations<String, String> boundZSetOperations = redisTemplate.boundZSetOps(smsLimitKey);

        // 使用RedisTemplate执行zrangeByScore操作
        Set<String> scoreSet = boundZSetOperations.rangeByScore(twentyFourHoursAgo / 1.0, currentTime / 1.0).stream().map(Object::toString).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(scoreSet)) {
            return;
        }
        ApiAssert.fail(scoreSet.size() >= 10, SMS_SEND_LIMIT_DAY);

        Set<Double> scoreDoubleSet = scoreSet.stream().map(Double::valueOf).collect(Collectors.toSet());
        Set<Double> filterByHourSet = scoreDoubleSet.stream().filter(time -> time > oneHoursAgo)
                .collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(filterByHourSet)) {
            return;
        }
        ApiAssert.fail(filterByHourSet.size() >= 5, SMS_SEND_LIMIT_HOUR);

        Set<Double> filterByMinuteSet = scoreDoubleSet.stream().filter(time -> time > oneMinuteAgo)
                .collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(filterByMinuteSet)) {
            return;
        }
        ApiAssert.fail(filterByMinuteSet.size() >= 1, SMS_SEND_LIMIT_MINUTE);
    }

    /**
     * 设置发送限制
     *
     * @param phone 手机号
     */
    private void setSendLimit(String phone) {
        String smsLimitKey = RedisKeyEnum.SMS_LIMIT.getKey() + phone;
        long currentTime = System.currentTimeMillis() / 1000;

        // 获取当前时间的字符串表示
        String currentTimeStr = String.valueOf(currentTime);
        // 将当前时间作为元素，其数值作为分数添加到有序集合中
        redisTemplate.opsForZSet().add(smsLimitKey, currentTimeStr, (double) currentTime);

        // 设置键的过期时间
        redisTemplate.expire(smsLimitKey, SMS_LIMIT_REDIS_TIMEOUT, TimeUnit.SECONDS);
    }

}
